#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>

#include "Manager.h"

Manager* managerConstruct()
{
	Manager *manager;
	manager = (Manager*)malloc(sizeof(Manager));
	return manager;
}

Manager* managerConstructWithShaft(Shaft* shaft)
{
	Manager *manager = managerConstruct();
	manager->shafts = listConstruct(elementConstruct(shaft));
	return manager;
}

void managerDeconstruct(Manager *manager)
{
	if(manager->shafts->count > 0)
	{
		listPrepareForLooping(manager->shafts);
		Element *element;

		while ((element = listNextElement(manager->shafts)) != NULL)
		{
			Shaft *shaft = (Shaft*)element->value;
			elevatorDeconstruct(shaft->elevator);
		}
	}

	listDeconstruct(manager->shafts);
	free(manager);
}

void managerAddShaft(Manager *manager, Shaft *shaft)
{
	listAddElement(manager->shafts, elementConstruct(shaft));
}

// Strategy one (Jordy)
Shaft* shaftStrategyOne(Manager *manager, Destination *destination, int currentFloor)
{
	Shaft *currentShaft;
	Shaft *chosenShaft;
	listPrepareForLooping(manager->shafts);
	// BUG: We aint checkin lowestFloor & highestFloor here
	currentShaft = chosenShaft = (Shaft*)listNextElement(manager->shafts)->value;

	while (currentShaft != NULL)
	{
		int currentFloorDifference = currentShaft->elevator->currentFloor < destination->floor
			? destination->floor - currentShaft->elevator->currentFloor
			: currentShaft->elevator->currentFloor - destination->floor;

		int chosenFloorDifference = chosenShaft->elevator->currentFloor < destination->floor
			? destination->floor - chosenShaft->elevator->currentFloor
			: chosenShaft->elevator->currentFloor - destination->floor;

		if (destination->floor <= chosenShaft->highestFloor &&
			destination->floor >= chosenShaft->lowestFloor &&
			currentFloorDifference < chosenFloorDifference)
			chosenShaft = currentShaft;

		Element *element = listNextElement(manager->shafts);
		if(element == NULL)
			currentShaft = NULL;
		else
			currentShaft = (Shaft*)element->value;
	}

	return chosenShaft;
}

// Strategy two (Rick)
Shaft* shaftStrategyTwo(Manager *manager, Destination *destination, int currentFloor)
{
	Shaft *currentShaft = NULL;
	ShaftScore *bestScore = NULL, *currentScore, *previousScore = NULL;
	int goalFloor = destination->floor;
	elevatorPriority prio = destination->priority;

	// we've already established that there are MORE than one shaft available
	listPrepareForLooping(manager->shafts); // set currentElement to firstElement
	currentShaft = (Shaft*) listNextElement(manager->shafts)->value;
	
	while (currentShaft != NULL)
	{
		// and here we're going to have to do some serious algorithmizing
		currentScore = shaftScoreConstruct(currentShaft);
		currentScore = shaftScoreGradeShaft(currentScore, goalFloor, currentFloor);

		if (currentScore == NULL || previousScore == NULL)
			bestScore = previousScore = currentScore;
		else
		{
			if (currentScore->grade > bestScore->grade)
				bestScore = currentScore;
		}

		// and prepare for the next iteration of the loop
		previousScore = currentScore;

		// or better yet let's first make sure we don't create an infinite loop..
		Element *nextElement = listNextElement(manager->shafts); // move the pointer to the next shaft 
		
		if (nextElement != NULL)
			currentShaft = (Shaft*) nextElement->value;
		else
			currentShaft = NULL;

	}

	return bestScore->shaft;
}

//Strategy three (Roy)
static int currentShaftIndex = 0;
Shaft* shaftStrategyThree(Manager *manager, Destination *destination, int currentFloor)
{
	Shaft *currentShaft;
	int maxShafts = manager->shafts->count;
	int tempInt = 0;
	
	
	// we've already established that there are MORE than one shaft available
	listPrepareForLooping(manager->shafts); // set currentElement to firstElement
	//This strategie, makes sure all the elevators will get used after each other.
	if (currentShaftIndex < maxShafts)
	{
		
		for (tempInt; tempInt <= currentShaftIndex; tempInt++)
		{
			currentShaft = (Shaft*) listNextElement(manager->shafts)->value;
		}
		
		currentShaftIndex++;
	}
	else
	{
		currentShaft = (Shaft*) listNextElement(manager->shafts)->value;
		currentShaftIndex = 0;
	}

	return currentShaft;
}

// Strategy wrapper method
Shaft* managerSelectShaftForDispatch(Manager *manager, Destination *destination, int currentFloor, int chosenStrategy)
{
	Shaft *shaft;

	// If there's no shaft at all..
	if(manager->shafts == NULL)
		return NULL;

	// If there's only one shaft...
	if (manager->shafts->count == 1)
	{
		Shaft *shaft = (Shaft*)listElementAtIndex(manager->shafts, 0)->value;
	
		if(destination->floor > shaft->highestFloor || destination->floor < shaft->lowestFloor)
			return NULL;
		else
			return shaft;
	}

	switch (chosenStrategy)
	{
		case 1:
			shaft = shaftStrategyOne(manager, destination, currentFloor);
			break;

		case 2:
			shaft = shaftStrategyTwo(manager, destination, currentFloor);
			break;

		case 3:
			shaft = shaftStrategyThree(manager, destination, currentFloor);
			break;

		default:
			shaft = shaftStrategyOne(manager, destination, currentFloor);
			break;
	}

	return shaft;
}

void managerSendEventToShaft(Shaft *shaft, elevatorEvent eventToExecute)
{
	shaftSendEvent(shaft, eventToExecute);
}

Shaft* managerGetShaftById(Manager *manager, int shaftId)
{
	Shaft *shaft = (Shaft*) listElementAtIndex(manager->shafts, shaftId)->value;

	return shaft;
}